﻿using System;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

namespace Remote_Server
{
    public class Client
    {
        public string ClientName;
        public TcpClient ClientSocket;
        public int ClientNumber;
        public Thread ClientThread;

        private byte[] sendBuffer;
        private byte[] readBuffer;
        private string InText;
        private string OutText;

        private ResponceClass GetResponce;
        private NetworkStream NetworkStream;

        public delegate void MsgDelegate(string text);
        public MsgDelegate Msg;

        public Client(string clName, int clNumber, TcpClient clSocket)
        {
            ClientName = clName;
            ClientNumber = clNumber;
            ClientSocket = clSocket;

            ClientSocket.SendTimeout = 0;  //in milliseconds  0 is infinite
            ClientSocket.ReceiveTimeout = 0;

            ClientSocket.SendBufferSize = 1025;
            ClientSocket.ReceiveBufferSize = 1025;

            ClientThread = new Thread(Talk);
        }

        private void Talk()
        {
            try
            {
                NetworkStream = ClientSocket.GetStream();
                while (true)
                {

                    Msg("Reading from client " + ClientNumber);

                    ReadData();

                    InText = ToString(readBuffer);

                    Msg("Got message: " + InText + " recived from client " + ClientNumber);

                    GetResponce = new ResponceClass();
                    GetResponce.MakeResponce(InText);
                    OutText = GetResponce.ReturnMsg;

                    Msg("Sending message: " + OutText + " - as state: " + GetResponce.ResponceState.ToString());

                    sendBuffer = ToBytes(OutText);

                    WriteData();

                    ClearBuffers();

                }
            }
            catch (NotImplementedException)
            {

            }
        }

        private void CloseAndExit()
        {
            Msg("Closing client: " + ClientNumber);
            ClientSocket.Close();
            ClientThread.Abort();
            return;
        }

        private void ReadData()
        {
            try
            {
                byte[] sizeBytes = new byte[4];
                NetworkStream.Read(sizeBytes, 0, 4);

                if (sizeBytes[0] == 0) throw new System.IO.IOException();

                    int sizeInt = int.Parse(System.Text.Encoding.ASCII.GetString(sizeBytes));


                    readBuffer = new byte[sizeInt];

                    NetworkStream.Read(readBuffer, 0, sizeInt);
            }
            catch (System.IO.IOException)
            {
                MainForm.log.Info("Client Connection Broken. Closing client " + ClientNumber);
                CloseAndExit();
            }

            return;
        }

        private void ClearBuffers()
        {
            sendBuffer = null;
            readBuffer = new byte[1024];
            InText = "";
            OutText = "";
        }

        private void WriteData()
        {
            NetworkStream.Write(sendBuffer, 0, sendBuffer.Length);
            NetworkStream.Flush();

            Msg("Wrote " + OutText + " to client " + ClientNumber);
        }


        private string ToString(byte[] byteArray)
        {
            string ConvertedText = System.Text.Encoding.UTF8.GetString(byteArray,0,byteArray.Length);
            return ConvertedText;
        }

        private byte[] ToBytes(string textToConvert)
        {
            byte[] TextArr;
            TextArr = System.Text.Encoding.UTF8.GetBytes(textToConvert);

            int textSize = TextArr.Length;
            string textString = textSize.ToString().PadLeft(4,'0');

            byte[] ByteArr = new byte[textSize + 4];

            System.Text.Encoding.ASCII.GetBytes(textString, 0,textString.Length, ByteArr,0);

            System.Buffer.BlockCopy(TextArr, 0, ByteArr, textString.Length, textSize);
            return ByteArr;
        }

        

         public static string ComputeUpTime()
         {
             double nTicks = 0;
             int nDays = 0;
             int nHours = 0;
             int nMin = 0;
             int nSec = 0;
            
             nTicks = Environment.TickCount;
             nTicks = (int)nTicks / 1000;
             nDays = (int)(nTicks / (3600 * 24));
             nTicks = nTicks - ((int)(nTicks / (3600 * 24)) * (3600 * 24));
             nHours = (int)(nTicks / 3600);
             nTicks = nTicks - ((nTicks / 3600) * 3600);
             nMin = (int)(nTicks / 60);
             nTicks = nTicks - ((int)(nTicks / 60) * 60);
             nSec = (int)nTicks;
            
             return nDays + ":" + nHours + ":" + nMin + ":" + nSec;
         }

         public static string GetDrives()
         {
            
             string Drives = "";
             System.IO.DriveInfo[] getInfo;
             getInfo = System.IO.DriveInfo.GetDrives();
             foreach (System.IO.DriveInfo info in getInfo) {
                 if (info.IsReady)
                 {
                     Drives +=
                         info.VolumeLabel + ": " +
                         info.AvailableFreeSpace.ToString() + "/" +
                         info.TotalSize.ToString();
                 }
             }
             return Drives;
         }

         public static string GetStatus()
         { 
             PerformanceCounter cpuCounter;
             PerformanceCounter ramCounter;

             cpuCounter = new PerformanceCounter();

             cpuCounter.CategoryName = "Processor";
             cpuCounter.CounterName = "% Processor Time";
             cpuCounter.InstanceName = "_Total";

             ramCounter = new PerformanceCounter();

             ramCounter.CategoryName = "Memory";
             ramCounter.CounterName = "Available MBytes";


             string StatusMsg =
                  Environment.MachineName + "\n" +
                 //"Free mem: " + Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1048576) + " mb" + "\n" + 
                 //"Free page: " + Math.Round(My.Computer.Info.AvailableVirtualMemory / 1048576) + " mb" + "\n" + 
                 //"Total mem: " + Math.Round(My.Computer.Info.TotalPhysicalMemory / 1048576) + " mb" + "\n" + 
                 //"Total page: " + Math.Round(My.Computer.Info.TotalVirtualMemory / 1048576) + " mb" + "\n" + 
                 "Free mem" + ramCounter.NextValue().ToString() + "\n" +
                 "Uptime: " + ComputeUpTime() + "\n" +
                 "Shutdown started: " + Environment.HasShutdownStarted + "\n" +
                 "Cpu: " + cpuCounter.NextValue().ToString() + "%" + "\n" + 
                 "Drives: " + GetDrives() + "%" + "\n" + 
                 "Uptime: " + ComputeUpTime();

             return StatusMsg;
         }

    }
}
